#include "syscall.h"
#include "print.c"


/* constant for tweaking the algorithms */
const int MAIN_IDLE_TICK = 10;			/* number of ticks the main thread will yield for everything */
const int MANAGER_IDLE_TICK = 10;		/* number of ticks the manager thread will yield and check for customers */
const int STOCKBOY_AISLE_TICK = 10;		/* number of ticks the stock boy will stay in each aisle */
const int STOCKBOY_STOCKROOM_TICK = 1;	/* number of ticks the stock boy will take in the stock room to re-stock items. */
const int MONEY_CHECK_TICK = 20;		/* number of ticks between the time the manager will check the cash registers */
const int ANNOUNCEMENT_TICK = 20;


#define NUM_MANAGERS 1				/* number of managersNUM_CLERKS */
#define NUM_CLERKS 3				/* number of clerks */
#define NUM_CUSTOMERS 20			/* number of customers */
#define NUM_REGISTERS 3				/* number of cash registers */
#define NUM_STOCKBOYS 3				/* number of stock boys */
#define NUM_AISLES 10				/* number of aisles/shelves */
#define INIT_ITEMS 3				/* default number of items per aisles/shelves */
#define MIN_ITEMS 3					/* default minimum of items before the stock boys are called to restock */
#define FALSE 0
#define TRUE  1				
#define ON_BREAK 0
#define AT_WORK 1	


const int MAX_CLERKLINELENGTH = 4;		/* max number of customers waiting in any line before more clerks are brought in */
const int CLERK_IDLE_TICK = 4;
const int STOCKBOY_IDLE_TICK = 0;
const int WAIT_TO_HELP = 1;
const int NOT_WAIT_TO_HELP = -1;

/*enum WorkStatus { AT_WORK, ON_BREAK };*/


/* monitor for cleaning up threads */
int cleanupLock;				/* the lock for cleaning up the threads */
int cleanupCV;				/* CV for clean */
int cleanupFlag = FALSE;
int cleanupThreads = 0;

/* monitor for stopping simulation */
int customerLock;				/* the lock for the number of customers */
int customerThreads = 0;			/* the number of customers coming in */

/* monitor for clerk wait line monitor variables */
int clerkLineLock;				/* main lock for looking at clerk lines */
int clerkLineCVs[NUM_CLERKS];		/* specific clerk line wait CV */
int clerkStates[NUM_CLERKS];		/* clerk status, either at work or on break */
int clerkLineLengths[NUM_CLERKS];		/* the number of customers waiting in each line */
int clerkWakeupFlag = FALSE;			/* the flag to wake up more clerks */   /****BOOLEAN******/
int clerkWakeupCV;			/* the CV for waiting for clerks to come back to work */
int clerkWakeupID = -1;
int clerkWakeupIDs[NUM_CLERKS];	/*****************************************************LIST***********************************************/
int clerkWakeupLine = 0;
int clerkOnbreakCV;			/* the CV for clerks on break */
int clerkOnbreakLine = 0;

/*monitor for clerk specific wait line monitor variables */
int clerkLineLocks[NUM_CLERKS];		/* locks to each individual clerk line */
int clerkLineTransCVs[NUM_CLERKS];	/* clerk-customer interaction CV */
int clerkLineCustomerIDs[NUM_CLERKS];		/* indicating the customer that is in transaction with clerk */
int clerkLineItems[NUM_CLERKS];			/* item handling between customer and clerk */
int clerkLinePayments[NUM_CLERKS];		/* indicating the money transfer from customer to clerk */
int clerkLineTotals[NUM_CLERKS];		/* indicating the total amount the items cost */
int clerkLineCashes[NUM_CLERKS];		/* indicating the money transfer from clerk to customer */
int clerkLineReturns[NUM_CLERKS];		/* flag to tell if the transaction is return or purchase */  /****BOOLEAN******/

/* monitors for registers */
int registerLocks[NUM_REGISTERS];
int registerCVs[NUM_REGISTERS];		/* register CV between clerk and register */
int registerEmptyCVs[NUM_REGISTERS];	/* register CV between manager and register, for emptying the register */
int registerMoneyCVs[NUM_REGISTERS];	/* register CV between manager and register, for asking for money */
int registerReturns[NUM_REGISTERS];		/* flag to tell if the transaction is return or purchase */
int registerCustomerIDs[NUM_REGISTERS];		/* mv telling the register the customer ID from clerk */
int registerItems[NUM_REGISTERS];		/* item handling between clerk to register */
int registerTotals[NUM_REGISTERS];		/* mv between clerk and register, the total cost of items */
int registerPayments[NUM_REGISTERS];		/* mv between clerk and register, the money paid by customers */
int registerCashes[NUM_REGISTERS];		/* mv between clerk and register, the money paid to customers */
int registerLines[NUM_REGISTERS];		/* indicating if a clerk is waiting for a register */
int registerEmptyLines[NUM_REGISTERS];		/* indicating if a manager is waiting to emptying register */
int registerMoneyLines[NUM_REGISTERS];		/* indicating if a register is waiting to get money from manager */
int registerMoneys[NUM_REGISTERS];		/* mv between manager and register, how much money register has right now */
int registerManagerMoneys[NUM_REGISTERS];	/* mv between manager and register, the money the manager is giving to register */

/* monitors for stock boys and restocking */
int stockBoyStatusLock;
int stockBoyOnbreakCV;			/* the CV for stock boys on break */
int stockBoyOnbreakLine = 0;
int stockBoyStates[NUM_STOCKBOYS];
int stockBoyAisles[NUM_STOCKBOYS];
int stockBoyAisleHelps[NUM_STOCKBOYS];
int stockBoyLocks[NUM_STOCKBOYS];
int stockBoyCVs[NUM_STOCKBOYS];
int stockBoyItems[NUM_STOCKBOYS];
int stockBoyCustomerIDs[NUM_STOCKBOYS];

/* monitors for stock boys and customers in channel helping, the extra locks/conditions/lines are for the customers that cannot find available stock boys in all the aisles, thus in the common waiting area */
int aisleHelpLocks[NUM_AISLES+1];
int aisleHelpCVs[NUM_AISLES+1];
int aisleHelpLines[NUM_AISLES+1];
int aisleHelpFlag = FALSE;

/* monitor for aisles and aisle items */
int aisleLock;				/* the lock for the aisles */
int aisleLocks[NUM_AISLES];			/* the lock for each aisle shelf */
int aisleItemCVs[NUM_AISLES];		/* the CV for waiting for the aisle shelf to be restocked */
int aisleItems[NUM_AISLES];			/* the number of items per aisle shelf */
int aisleRestockItems[NUM_AISLES];		/* the number of items to be restocked per aisle shelf */

/* monitor for stock room */
int stockRoomLock;
int stockRoomWaitLock;
int stockRoomWaitCV;
int stockRoomStockBoyID;
int stockRoomWaitLine = 0;

/* aisle/shelf item prices */
int itemPrices[NUM_AISLES];


/*variables for each roles, such as register_id, customer_id and so on.*/
int registerCountLock;
int registerCount = 0;
int clerkCountLock;
int clerkCount = 0;
int customerCountLock;
int customerCount = 0;
int stockboyCountLock;
int stockboyCount = 0;


/*RADOM COUNTER since there is no rand() supported*/
int randCount = 0;


void Initializes(){
	int i;
	int Numbers[2];
	int ManagerNum[1] = {NUM_MANAGERS};
	int ClerkNum[1] = {NUM_CLERKS};
	int CustomerNum[1] = {NUM_CUSTOMERS};
	int RegisterNum[1] = {NUM_REGISTERS};
	int StockboyNum[1] = {NUM_STOCKBOYS};
	int AisleNum[1] = {NUM_AISLES};

	/* thread shutdown related monitor objects */
	cleanupLock = CreateLock();
	cleanupCV = CreateCondition();
	cleanupFlag = FALSE;
	cleanupThreads = 0;

	/* customer related monitor objects */
	customerLock = CreateLock();
	customerThreads = 0;

	/* clerk line related monitor objects */
	clerkLineLock = CreateLock();
	for (i = 0; i < NUM_CLERKS; i++) {
		clerkLineCVs[i] = CreateCondition();
		clerkStates[i] = ON_BREAK;
		clerkLineLengths[i] = 0;
		clerkWakeupIDs[i] = -1;  /*****LIST******/
	}
	clerkWakeupFlag = FALSE;
	clerkWakeupCV = CreateCondition();
	clerkWakeupID = -1;
/*	clerkWakeupIDs = new List;  */
	clerkWakeupLine = 0;
	clerkOnbreakCV = CreateCondition();
	clerkOnbreakLine = 0;

	/* individual clerk line related monitor objects */
	for ( i = 0; i < NUM_CLERKS; i++) {
		clerkLineLocks[i] = CreateLock();
		clerkLineTransCVs[i] = CreateCondition();
		clerkLineCustomerIDs[i] = -1;
		clerkLineItems[i] = -1;
		clerkLinePayments[i] = 0;
		clerkLineTotals[i] = 0;
		clerkLineCashes[i] = 0;
		clerkLineReturns[i] = FALSE;
	}

	/* individual cash register related monitor objects */
	for ( i = 0; i < NUM_REGISTERS; i++) {
		registerLocks[i] = CreateLock();
		registerCVs[i] = CreateCondition();
		registerEmptyCVs[i] = CreateCondition();
		registerMoneyCVs[i] = CreateCondition();
		registerReturns[i] = FALSE;
		registerCustomerIDs[i] = -1;
		registerItems[i] = -1;
		registerPayments[i] = 0;
		registerCashes[i] = 0;
		registerLines[i] = 0;
		registerEmptyLines[i] = 0;
		registerMoneyLines[i] = 0;
		registerTotals[i] = 0;
		registerMoneys[i] = 0;
		registerManagerMoneys[i] = 0;
	}

	/* individual aisle/shelf related monitor objects */
	aisleLock = CreateLock();
	for ( i = 0; i < NUM_AISLES; i++) {
		aisleLocks[i] = CreateLock();
		aisleItemCVs[i] = CreateCondition();
		aisleItems[i] = INIT_ITEMS;
		aisleRestockItems[i] = 0;
	}

	/* stock room related monitor objects */
	stockRoomLock = CreateLock();
	stockRoomWaitLock = CreateLock();
	stockRoomWaitCV = CreateCondition();
	stockRoomStockBoyID = -1;
	stockRoomWaitLine = 0;


	for ( i = 0; i < (NUM_AISLES+1); i++) {
		aisleHelpLocks[i] = CreateLock();
		aisleHelpCVs[i] = CreateCondition();
		aisleHelpLines[i] = 0;
	}
	aisleHelpFlag = FALSE;

	/* stock boy related monitor objects */
	stockBoyStatusLock = CreateLock();
	stockBoyOnbreakCV = CreateCondition();
	stockBoyOnbreakLine = 0;
	for ( i = 0; i < NUM_STOCKBOYS; i++) {
		stockBoyLocks[i] = CreateLock();
		stockBoyCVs[i] = CreateCondition();
		stockBoyStates[i] = ON_BREAK;
		stockBoyAisles[i] = -1;
		stockBoyAisleHelps[i] = -1;
		stockBoyItems[i] = -1;
		stockBoyCustomerIDs[i] = -1;
	}

	for ( i = 0; i < NUM_AISLES; i++) {
		itemPrices[i] = i+1;
	}
	/*lock for counting each role*/
	registerCountLock = CreateLock();
	clerkCountLock = CreateLock();
	customerCountLock = CreateLock();
	stockboyCountLock = CreateLock();

	printf("Number of Managers = [%d]\n", ManagerNum);
	printf("Number of Clerks = [%d]\n", ClerkNum);
	printf("Number of Customers = [%d]\n", CustomerNum);
	printf("Number of CashRegisters = [%d]\n", RegisterNum);
	printf("Number of StockBoys = [%d]\n", StockboyNum);
	printf("Number of Aisle = [%d]\n", AisleNum);
	printString("Items:\n");
	for ( i = 0; i < NUM_AISLES; i++) {
		Numbers[0] = i;
		Numbers[1] = itemPrices[i];
		printf("[%d] - $[%d]\n", Numbers);
	}
}

void Cleanups() {
	int i;

	/* thread shutdown related monitor objects */
	DestroyLock(cleanupLock);
	DestroyCondition(cleanupCV);

	/* customer related monitor objects */
	DestroyLock(customerLock);

	/* clerk line related monitor objects */
	DestroyLock(clerkLineLock);
	for ( i = 0; i < NUM_CLERKS; i++) {
		DestroyCondition(clerkLineCVs[i]);
	}
	DestroyCondition(clerkWakeupCV);
/*	delete clerkWakeupIDs;*/
	DestroyCondition(clerkOnbreakCV);

	/* individual clerk line related monitor objects */
	for ( i = 0; i < NUM_CLERKS; i++) {
		DestroyLock(clerkLineLocks[i]);
		DestroyCondition(clerkLineTransCVs[i]);
	}

	/* individual cash register related monitor objects */
	for ( i = 0; i < NUM_REGISTERS; i++) {
		DestroyLock(registerLocks[i]);
		DestroyCondition(registerCVs[i]);
		DestroyCondition(registerEmptyCVs[i]);
		DestroyCondition(registerMoneyCVs[i]);
	}

	/* individual aisle/shelf related monitor objects */
	DestroyLock(aisleLock);
	for ( i = 0; i < NUM_AISLES; i++) {
		DestroyLock(aisleLocks[i]);
		DestroyCondition(aisleItemCVs[i]);
	}

	for ( i = 0; i < NUM_AISLES+1; i++) {
		DestroyLock(aisleHelpLocks[i]);
		DestroyCondition(aisleHelpCVs[i]);
	}

	/* stock room related monitor objects */	
	DestroyLock(stockRoomLock);
	DestroyLock(stockRoomWaitLock);
	DestroyCondition(stockRoomWaitCV);

	/* stock boy related monitor objects */
	DestroyLock(stockBoyStatusLock);
	DestroyCondition(stockBoyOnbreakCV);
	for (i = 0; i < NUM_STOCKBOYS; i++) {
		DestroyLock(stockBoyLocks[i]);
		DestroyCondition(stockBoyCVs[i]);
	}

	/*destroy locks created for counting each role*/
	DestroyLock(registerCountLock);
	DestroyLock(clerkCountLock);
	DestroyLock(customerCountLock);
	DestroyLock(stockboyCountLock);

}


void Clerk() {
	int breakCounter = 0;
	int clerk_id;
	int printMsg[5];

	Acquire(clerkCountLock);
	clerk_id = clerkCount;
	clerkCount++;
	Release(clerkCountLock);

	printMsg[0] = clerk_id;
	/*printf("Clerk %d is coming to work.\n", printMsg);*/
	Acquire(cleanupLock);
	cleanupThreads++;
	Release(cleanupLock);

	Acquire(clerkLineLock);
	clerkStates[clerk_id] = AT_WORK;
	Release(clerkLineLock);

	while (TRUE) {
		/* check to see if more than 4 customers waiting in line */
		Acquire(clerkLineLock);
		if (clerkLineLengths[clerk_id] >= MAX_CLERKLINELENGTH) {
/*			printf("Clerk [%d] sees more than %d people in line and calls Manager.\n", clerk_id, MAX_CLERKLINELENGTH);*/
			printMsg[0] = clerk_id;
			printMsg[1] = MAX_CLERKLINELENGTH;
			printf("Clerk [%d] sees more than %d people in line and calls Manager.\n", printMsg );
			clerkWakeupFlag = TRUE;
			/* clerkWakeupIDs->Append((void *)&clerk_id); */
			clerkWakeupIDs[clerk_id] = 1;
		}

		/*check to see if customers are waiting fo this particular line */
		if (clerkLineLengths[clerk_id] > 0) {
			breakCounter = 0;
			/* signal first customer waiting in this line */
			Signal(clerkLineCVs[clerk_id], clerkLineLock);

			/* grab own lock to start customer-clerk interaction */
			Acquire(clerkLineLocks[clerk_id]);
			clerkLinePayments[clerk_id] = 0;
			clerkLineTotals[clerk_id] = 0;
			clerkLineCashes[clerk_id] = 0;
			Release(clerkLineLock);

			/* grab the register first */
			Acquire(registerLocks[clerk_id]);
			registerLines[clerk_id]++;
			Wait(registerCVs[clerk_id], registerLocks[clerk_id]);
			registerLines[clerk_id]--;

			/* wait for the customer to tell if it's a purchase or return */
			clerkLineItems[clerk_id] = 999;
			Wait(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);

			/* tell the register the type of transaction purchase or return */
			registerReturns[clerk_id] = clerkLineReturns[clerk_id];
			registerCustomerIDs[clerk_id] = clerkLineCustomerIDs[clerk_id];
			Signal(registerCVs[clerk_id], registerLocks[clerk_id]);
			Wait(registerCVs[clerk_id], registerLocks[clerk_id]);

			while (clerkLineItems[clerk_id] != -1) {
				/* wait for customer to hand over item */
				/* signal customer to hand over another item */
/*				printf("Clerk [%d] got item [%d] from Customer [%d].\n", clerk_id, clerkLineItems[clerk_id], clerkLineCustomerIDs[clerk_id]);*/
				printMsg[0] = clerk_id;
				printMsg[1] = clerkLineItems[clerk_id];
				printMsg[2] = clerkLineCustomerIDs[clerk_id];
				printf("Clerk [%d] got item [%d] from Customer [%d].\n", printMsg);
				Signal(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);

				/* signal register to scan items */
				registerItems[clerk_id] = clerkLineItems[clerk_id];
/*				printf("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n", clerk_id, clerkLineItems[clerk_id], clerk_id);*/
				printMsg[0] = clerk_id;
				printMsg[1] = clerkLineItems[clerk_id];
				printMsg[2] = clerk_id;
				printf("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n", printMsg);
				Signal(registerCVs[clerk_id], registerLocks[clerk_id]);
				Wait(registerCVs[clerk_id], registerLocks[clerk_id]);
				
				Wait(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);
			}

			/* tell the register all items are done, wait for the total $ */
			registerItems[clerk_id] = clerkLineItems[clerk_id];
			Signal(registerCVs[clerk_id], registerLocks[clerk_id]);
			Wait(registerCVs[clerk_id], registerLocks[clerk_id]);
			clerkLineTotals[clerk_id] = registerTotals[clerk_id];
/*			printf("Clerk [%d] got total cost $[%d] from Cash Register [%d].\n", clerk_id, registerTotals[clerk_id], clerk_id);*/
			printMsg[0] = clerk_id;
			printMsg[1] = registerTotals[clerk_id];
			printMsg[2] = clerk_id;
			printf("Clerk [%d] got total cost $[%d] from Cash Register [%d].\n", printMsg);

			/* transaction is return, signal the register it knows, and wait for the money from clerk */
			if (clerkLineReturns[clerk_id]) {
/*				printf("Clerk [%d] tells Customer [%d] total cost is $[%d].\n", clerk_id, clerkLineCustomerIDs[clerk_id], registerTotals[clerk_id]);*/
				printMsg[0] = clerk_id;
				printMsg[1] = clerkLineCustomerIDs[clerk_id];
				printMsg[2] = registerTotals[clerk_id];
				printf("Clerk [%d] tells Customer [%d] total cost is $[%d].\n", printMsg);
				Signal(registerCVs[clerk_id], registerLocks[clerk_id]);
				Wait(registerCVs[clerk_id], registerLocks[clerk_id]);
/*				printf("Clerk [%d] got money $[%d] from Cash Register [%d].\n", clerk_id, registerCashes[clerk_id], clerk_id);*/
				printMsg[0] = clerk_id;
				printMsg[1] = registerCashes[clerk_id];
				printMsg[2] = clerk_id;
				printf("Clerk [%d] got money $[%d] from Cash Register [%d].\n", printMsg);

				clerkLineCashes[clerk_id] = registerCashes[clerk_id];
/*				printf("Clerk [%d] gave the money $[%d] to Customer [%d].\n", clerk_id, clerkLineCashes[clerk_id], clerkLineCustomerIDs[clerk_id]);*/
				printMsg[0] = clerk_id;
				printMsg[1] = registerCashes[clerk_id];
				printMsg[2] = clerkLineCustomerIDs[clerk_id];
				printf("Clerk [%d] gave the money $[%d] to Customer [%d].\n", printMsg);
				/* wait for customer to acknowledge the money received */
				Signal(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);
				Wait(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);

				/* signal the cash register for the receipt */
				Signal(registerCVs[clerk_id], registerLocks[clerk_id]);
				Wait(registerCVs[clerk_id], registerLocks[clerk_id]);
			}
			/* transaction is purchase, wait for payment */
			else {
				clerkLineTotals[clerk_id] = registerTotals[clerk_id];
/*				printf("Clerk [%d] tells Customer [%d] total cost is $[%d].\n", clerk_id, clerkLineCustomerIDs[clerk_id], clerkLineTotals[clerk_id]);*/
				printMsg[0] = clerk_id;
				printMsg[1] = clerkLineCustomerIDs[clerk_id];
				printMsg[2] = clerkLineTotals[clerk_id];
				printf("Clerk [%d] tells Customer [%d] total cost is $[%d].\n", printMsg);
				Signal(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);
				Wait(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);

/*				printf("Clerk [%d] got money $[%d] from Customer [%d].\n", clerk_id, clerkLinePayments[clerk_id], clerkLineCustomerIDs[clerk_id]);*/
				printMsg[0] = clerk_id;
				printMsg[1] = clerkLinePayments[clerk_id];
				printMsg[2] = clerkLineCustomerIDs[clerk_id];
				printf("Clerk [%d] got money $[%d] from Customer [%d].\n", printMsg);
				registerPayments[clerk_id] = clerkLinePayments[clerk_id];
/*				printf("Clerk [%d] gave the money $[%d] to Cash Register [%d].\n", clerk_id, registerPayments[clerk_id], clerk_id);*/
				printMsg[0] = clerk_id;
				printMsg[1] = clerkLinePayments[clerk_id];
				printMsg[2] = clerk_id;
				printf("Clerk [%d] gave the money $[%d] to Cash Register [%d].\n", printMsg);
				Signal(registerCVs[clerk_id], registerLocks[clerk_id]);
				Wait(registerCVs[clerk_id], registerLocks[clerk_id]);
			}

			/* give customer the recipt */
/*			printf("Clerk [%d] gave the receipt to Customer [%d] and tells him to leave.\n", clerk_id, clerkLineCustomerIDs[clerk_id]);*/
			printMsg[0] = clerk_id;
			printMsg[1] = clerkLineCustomerIDs[clerk_id];
			printf("Clerk [%d] gave the receipt to Customer [%d] and tells him to leave.\n", printMsg);
			Signal(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);
			Wait(clerkLineTransCVs[clerk_id], clerkLineLocks[clerk_id]);

			/* release the register */
			Release(registerLocks[clerk_id]);

			/* release the lock, we are done with this customer */
			Release(clerkLineLocks[clerk_id]);
		} else {

			breakCounter++;

			if (breakCounter >= CLERK_IDLE_TICK) {
				breakCounter = 0;
				/* leave the register and go on break */
				Acquire(cleanupLock);
				if (cleanupFlag == FALSE) {
/*					printf("Clerk [%d] is leaving Cash Register [%d] and going on break.\n", clerk_id, clerk_id);*/
					printMsg[0] = clerk_id;
					printMsg[1] = clerk_id;
					printf("Clerk [%d] is leaving Cash Register [%d] and going on break.\n", printMsg);
				}
				Release(cleanupLock);
				clerkStates[clerk_id] = ON_BREAK;
				clerkOnbreakLine++;
				Wait(clerkOnbreakCV, clerkLineLock);
				Acquire(cleanupLock);
				if (cleanupFlag == FALSE) {
/*					printf("Clerk [%d] was called by Manager to work.\n", clerk_id);*/
					printMsg[0] = clerk_id;
					printf("Clerk [%d] was called by Manager to work.\n", printMsg);
				}
				Release(cleanupLock);
				clerkOnbreakLine--;
				clerkStates[clerk_id] = AT_WORK;
				Release(clerkLineLock);
			}
			else {
				Release(clerkLineLock);
			}
		}

		/* if no more customers, stop the while loop, otherwise, continue */
		Acquire(cleanupLock);
		if (cleanupFlag == TRUE) {
			Release(cleanupLock);
			break;
		}
		Release(cleanupLock);

		Yield();
	}
	randCount++;

	Acquire(cleanupLock);
	cleanupThreads--;
	Signal(cleanupCV, cleanupLock);
	Release(cleanupLock);
	printMsg[0] = clerk_id;
	/*printf("Clerk %d is offline.\n", printMsg);*/
	Exit(0);
}


void Customer() {
	int shortestLineIndex = -1;
	int shortestLineLength = 999;
	int i, j, k;
	int printMsg[3];
	int customer_id;

	int items[NUM_AISLES];
	int totalItems = 0;
	int stockBoyAisle = -1;
	int returnFlag = FALSE;
	int stockBoyFoundFlag = FALSE;
	int totalItemCount = 0;
	int aisleHelpStockBoyID = -1;

	Acquire(cleanupLock);
	cleanupThreads++;
	Release(cleanupLock);
	
	/* increment the customer counter every time a customer enters */
	Acquire(customerLock);
	customerThreads++;
	Release(customerLock);

	Acquire(customerCountLock);
	customer_id = customerCount;
	customerCount++;
	printMsg[0] = customer_id;
	/*printString("Customer %d is coming to shop.\n", printMsg);*/
	Release(customerCountLock);
	
	totalItems = 5;
/*	totalItems = rand()%10 + 1;*/

	/* randomize 1 to 10 items to buy */
/*	items.assign(totalItems, -1);*/
	for (i = 0; i < totalItems; i++) {
/*		items[i] = rand()%NUM_AISLES;*/
		items[i] = i+1;
	}

	/* determine the 20% of the time the customer return items */
	if (randCount%5 == 0) {
		/*returnFlag = TRUE;*/
	}
	if (customer_id%10 == 0){
		returnFlag = TRUE;
	}

	/* randomize 25% of the time the customer will need to find items from stock boys 
	   plus NUM_AISLES to indicate the fact that the item aisle will be asked */
	if (returnFlag == FALSE) {
		for (i = 0; i < totalItems; i++) {
			if (randCount%4 == 0) {
				/*items[i] += NUM_AISLES;*/
			}
			if (customer_id%10 == 1) {
				items[i] += NUM_AISLES;
			}
		}
	}
	
	if (returnFlag == TRUE) {
/*		printf("Customer [%d] needs to return [%d] no.of items.\n", customer_id, totalItems);*/
		printMsg[0] = customer_id;
		printMsg[1] = totalItems;
		printf("Customer [%d] needs to return [%d] no.of items.\n", printMsg);
	}
	else {
/*		printf("Customer [%d] wants to buy [%d] no.of items.\n", customer_id, totalItems);*/
		printMsg[0] = customer_id;
		printMsg[1] = totalItems;
		printf("Customer [%d] wants to buy [%d] no.of items.\n", printMsg);
	}

	/* find the items in aisles */
	if (returnFlag == FALSE) {
		for (i = 0; i < totalItems; i++) {
			/* if the items aisle/shelf is negative, find stock boys to help */
			if (items[i] != -1) {
				stockBoyAisle = -1;
	
				/* the item aisle number >= NUM_AISLES; ie, dunno where to find the item, try to find a stock boy */
				if (items[i] >= NUM_AISLES) {
/*					printf("Customer [%d] is not able to find item [%d] and is searching for StockBoy.\n", customer_id, items[i]-NUM_AISLES);*/
					printMsg[0] = customer_id;
					printMsg[1] = items[i]-NUM_AISLES;
					printf("Customer [%d] is not able to find item [%d] and is searching for StockBoy.\n", printMsg);
					for ( j = 0; j < NUM_AISLES; j++) {
						Acquire(aisleHelpLocks[j]);

						/* now we are at the aisle, look for stock boys */
						Acquire(stockBoyStatusLock);
						for (k = 0; k < NUM_STOCKBOYS; k++) {
							if (stockBoyStates[k] == AT_WORK && stockBoyAisles[k] == j) {
								stockBoyAisle = j;
								break;
							}
						}
						Release(stockBoyStatusLock);

						if (stockBoyAisle != -1) {
							aisleHelpLines[stockBoyAisle]++;
							Wait(aisleHelpCVs[stockBoyAisle], aisleHelpLocks[stockBoyAisle]);

							/* find a stock boy that signaled to help */
							Acquire(stockBoyStatusLock);
							for (k = 0; k < NUM_STOCKBOYS; k++) {
								if (stockBoyStates[k] == AT_WORK && stockBoyAisleHelps[k] == WAIT_TO_HELP && stockBoyAisles[k] == stockBoyAisle) {
									aisleHelpStockBoyID = k;
									stockBoyAisleHelps[k] = NOT_WAIT_TO_HELP;
									break;
								}
							}
							Release(stockBoyStatusLock);

							Acquire(stockBoyLocks[aisleHelpStockBoyID]);
							Release(aisleHelpLocks[stockBoyAisle]);
							

/*							printf("Customer [%d] is asking for assistance from StockBoy [%d].\n", customer_id, aisleHelpStockBoyID);*/
							printMsg[0] = customer_id;
							printMsg[1] = aisleHelpStockBoyID;
							printf("Customer [%d] is asking for assistance from StockBoy [%d].\n", printMsg);
							stockBoyCustomerIDs[aisleHelpStockBoyID] = customer_id;
							Signal(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);
							
							Wait(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);

							/* give the stock boy the item and ask for the aisle */
							stockBoyItems[aisleHelpStockBoyID] = items[i];
							Signal(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);

							/* wait for the stockboy to give the proper aisle for the item */
							Wait(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);
							items[i] = stockBoyItems[aisleHelpStockBoyID];

/*							printf("Customer [%d] got aisle [%d] from StockBoy [%d].\n", customer_id, items[i], aisleHelpStockBoyID);*/
							printMsg[0] = customer_id;
							printMsg[1] = items[i];
							printMsg[2] = aisleHelpStockBoyID;
							printf("Customer [%d] got aisle [%d] from StockBoy [%d].\n", printMsg);
							Release(stockBoyLocks[aisleHelpStockBoyID]);
							break;
						}
						else {
							Release(aisleHelpLocks[j]);
						}
					}

					/* cannot find an available stock boy in aisles, call manager */
					if (stockBoyAisle == -1) {
/*						printf("Customer [%d] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n", customer_id);*/
						printMsg[0] = customer_id;
						printf("Customer [%d] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n", printMsg);
						Acquire(aisleHelpLocks[NUM_AISLES]);
						aisleHelpFlag = TRUE;
						aisleHelpLines[NUM_AISLES]++;
						Wait(aisleHelpCVs[NUM_AISLES], aisleHelpLocks[NUM_AISLES]);
 
						/* find a stock boy that signaled to help */
						Acquire(stockBoyStatusLock);
						for (j = 0; j < NUM_STOCKBOYS; j++) {
							if (stockBoyStates[j] == AT_WORK && stockBoyAisleHelps[j] == WAIT_TO_HELP && stockBoyAisles[j] == NUM_AISLES) {
								aisleHelpStockBoyID = j;
								stockBoyAisleHelps[j] = NOT_WAIT_TO_HELP;
								break;
							}
						}
						Release(stockBoyStatusLock);

						Acquire(stockBoyLocks[aisleHelpStockBoyID]);
						Release(aisleHelpLocks[NUM_AISLES]);

/*						printf("Customer [%d] is asking for assistance from StockBoy [%d].\n", customer_id, aisleHelpStockBoyID);*/
						printMsg[0] = customer_id;
						printMsg[1] = aisleHelpStockBoyID;
						printf("Customer [%d] is asking for assistance from StockBoy [%d].\n", printMsg);
						stockBoyCustomerIDs[aisleHelpStockBoyID] = customer_id;
						Signal(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);
						
						Wait(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);

						/* give the stock boy the item and ask for the aisle */
						stockBoyItems[aisleHelpStockBoyID] = items[i];
						Signal(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);

						/* wait for the stockboy to give the proper aisle for the item */
						Wait(stockBoyCVs[aisleHelpStockBoyID], stockBoyLocks[aisleHelpStockBoyID]);
						items[i] = stockBoyItems[aisleHelpStockBoyID];

/*						printf("Customer [%d] got aisle [%d] from StockBoy [%d].\n", customer_id, items[i], aisleHelpStockBoyID);*/
						printMsg[0] = customer_id;
						printMsg[1] = items[i];
						printMsg[2] = aisleHelpStockBoyID;
						printf("Customer [%d] got aisle [%d] from StockBoy [%d].\n", printMsg);				
						Release(stockBoyLocks[aisleHelpStockBoyID]);
					}
					
					if (items[i] >= NUM_AISLES) {
						/* printf("*************Customer [%d] got aisle for item [%d]....from stockboy wrong\n", customer_id, items[i]); */
						items[i] -= NUM_AISLES;
					}
				}

				/* get the lock for the aisle/shelf before taking the items */
				Acquire(aisleLocks[items[i]]);
				while (aisleItems[items[i]] == 0) {
					/* printf("Customer [%d] is waiting for item [%d] to be restocked.\n", customer_id, items[i]); */
					Wait(aisleItemCVs[items[i]], aisleLocks[items[i]]);
					/* printf("Customer [%d] is trying to grab item [%d].\n", customer_id, items[i]); */
				}
				/* printf("Customer [%d] grabs the item [%d].\n", customer_id, items[i]); */
				aisleItems[items[i]]--;
				Release(aisleLocks[items[i]]);
			}
		}
	}

	/* find the clerk with shortest line */
	Acquire(clerkLineLock);
	while (TRUE) {
		shortestLineIndex = -1;
		shortestLineLength = 999;

		/* loop through all the clerk wait lines */
		for (i = 0; i < NUM_CLERKS; i++) {
			/* if the clerk is on break, find another one */
			if (clerkStates[i] == ON_BREAK) {
				continue;
			}

			/* check to see if the current wait line is shorter than the wait line we have in mind */
			if (clerkLineLengths[i] < shortestLineLength) {
				shortestLineIndex = i;
				shortestLineLength = clerkLineLengths[i];
			}
		}

		/* all clerks are on break, call manager */
		if (shortestLineIndex == -1) {
			/* printf("Customer %d cannot find an available clerk, calling Manager\n", customer_id); */
			clerkWakeupFlag = TRUE;
			clerkWakeupLine++;
			/* printf("Customer %d is waiting for an available clerk\n", customer_id); */
			Wait(clerkWakeupCV, clerkLineLock);
			clerkWakeupLine--;
			/* printf("Customer %d is finding a clerk again\n", customer_id); */
		}
		else {
			break;
		}
	}
	/* proceed to the clerk with shortest line */
/*	printf("Customer [%d] chose Clerk [%d] with line length of [%d].\n", customer_id, shortestLineIndex, shortestLineLength);*/
	printMsg[0] = customer_id;
	printMsg[1] = shortestLineIndex;
	printMsg[2] = shortestLineLength;
	printf("Customer [%d] chose Clerk [%d] with line length of [%d].\n", printMsg);
	clerkLineLengths[shortestLineIndex]++;

	Wait(clerkLineCVs[shortestLineIndex], clerkLineLock);
	clerkLineLengths[shortestLineIndex]--;

	/* grab the individual clerk line and tell the clerk the purchase/return type, and signal the clerk */
	Acquire(clerkLineLocks[shortestLineIndex]);
	Release(clerkLineLock);
	clerkLineCustomerIDs[shortestLineIndex] = customer_id;
	clerkLineReturns[shortestLineIndex] = returnFlag;


	/* Hand over all the items one at a time */
	for (i = 0; i < totalItems; i++) {
		if (items[i] != -1) {
			clerkLineItems[shortestLineIndex] = items[i];
/*			printf("Customer [%d] gives item [%d] to Clerk [%d].\n", customer_id, items[i], shortestLineIndex);*/
			printMsg[0] = customer_id;
			printMsg[1] = items[i];
			printMsg[2] = shortestLineIndex;
			printf("Customer [%d] gives item [%d] to Clerk [%d].\n", printMsg);
			Signal(clerkLineTransCVs[shortestLineIndex], clerkLineLocks[shortestLineIndex]);
			/*printf("Customer [%d] is signaling to hand over item no. [%d] to clerk [%d]\n", customer_id, items[i], shortestLineIndex);*/
			Wait(clerkLineTransCVs[shortestLineIndex], clerkLineLocks[shortestLineIndex]);
		}
	}

	/* printf("Customer %d is signaling to hand over items to clerk %d\n", customer_id, shortestLineIndex); */
	clerkLineItems[shortestLineIndex] = -1;
	Signal(clerkLineTransCVs[shortestLineIndex], clerkLineLocks[shortestLineIndex]);
/*	printf("Customer [%d] tells Clerk [%d], I have given you all my [%d] items.\n", customer_id, shortestLineIndex, totalItems);*/
	printMsg[0] = customer_id;
	printMsg[1] = shortestLineIndex;
	printMsg[2] = totalItems;
	printf("Customer [%d] tells Clerk [%d], I have given you all my [%d] items.\n", printMsg);
	Wait(clerkLineTransCVs[shortestLineIndex], clerkLineLocks[shortestLineIndex]);

	/* pay for the itmes or receive money from item */
	/* if customer is returning items, no need to pay, one less wait/signal */
	if (returnFlag == TRUE) {
/*		printf("Customer [%d] receives $[%d] from Clerk [%d] and is now waiting for receipt.\n", customer_id, clerkLineCashes[shortestLineIndex], shortestLineIndex);*/
		printMsg[0] = customer_id;
		printMsg[1] = clerkLineCashes[shortestLineIndex];
		printMsg[2] = shortestLineIndex;
		printf("Customer [%d] receives $[%d] from Clerk [%d] and is now waiting for receipt.\n", printMsg);
	}
	/* wait for the clerk to give the total cost and pay */
	else {
		clerkLinePayments[shortestLineIndex] = clerkLineTotals[shortestLineIndex];
/*		printf("Customer [%d] pays $[%d] to Clerk [%d] and is now waiting for receipt.\n", customer_id, clerkLineTotals[shortestLineIndex], shortestLineIndex);*/

		printMsg[0] = customer_id;
		printMsg[1] = clerkLineTotals[shortestLineIndex];
		printMsg[2] = shortestLineIndex;
		printf("Customer [%d] pays $[%d] to Clerk [%d] and is now waiting for receipt.\n", printMsg);
	}
	Signal(clerkLineTransCVs[shortestLineIndex], clerkLineLocks[shortestLineIndex]);

	/* wait for the recipt */
	Wait(clerkLineTransCVs[shortestLineIndex], clerkLineLocks[shortestLineIndex]);
/*	printf("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n", customer_id, shortestLineIndex);*/
	printMsg[0] = customer_id;
	printMsg[1] = shortestLineIndex;
	printf("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n", printMsg);
	Signal(clerkLineTransCVs[shortestLineIndex], clerkLineLocks[shortestLineIndex]);

	Release(clerkLineLocks[shortestLineIndex]);

	/* decrement the customer counter every time a customer leaves */
	Acquire(customerLock);
	customerThreads--;
	Release(customerLock);

	randCount++;

	/* thread shutdown */ 
	Acquire(cleanupLock);
	cleanupThreads--;
	Signal(cleanupCV, cleanupLock);
	Release(cleanupLock);
	printMsg[0] = customer_id;
	/*printf("Customer %d is offline.\n", printMsg);*/
	Exit(0);
}

void StockBoy() {
	int restockAisleIndex = -1;
	int restockFlag = FALSE;
	int helpFlag = FALSE;

	int printMsg[4];
	int i;
	int stockboy_id;

	Acquire(cleanupLock);
	cleanupThreads++;
	Release(cleanupLock);

	Acquire(stockboyCountLock);
	stockboy_id = stockboyCount;
	stockboyCount++;
	Release(stockboyCountLock);

	printMsg[0] = stockboy_id;
	/*printf("Stockboy [%d] is coming to work\n", printMsg);*/

	Acquire(stockBoyStatusLock);
	stockBoyStates[stockboy_id] = AT_WORK;
	Release(stockBoyStatusLock);

	while (TRUE) {
		restockAisleIndex = -1;
		restockFlag = FALSE;
		helpFlag = FALSE;

		/* if people are waiting to be helped, help them first. */
		Acquire(aisleHelpLocks[NUM_AISLES]);
		while (aisleHelpLines[NUM_AISLES] > 0) {
			helpFlag = TRUE;
			/* if there are customers waiting in the aisle to be helped, signal one of them */
			/*printf("SB [%d] found someone to help, put myself on the list, let them find me,\n", stockboy_id); */
			Acquire(stockBoyStatusLock);
			stockBoyAisles[stockboy_id] = NUM_AISLES;
			stockBoyAisleHelps[stockboy_id] = WAIT_TO_HELP;
			Release(stockBoyStatusLock);

			/* signal anyone waiting for help, one of them */
			Signal(aisleHelpCVs[NUM_AISLES], aisleHelpLocks[NUM_AISLES]);
			aisleHelpLines[NUM_AISLES]--;
				
			/* grab my own lock, wait for them to signal me */
			Acquire(stockBoyLocks[stockboy_id]);
			Release(aisleHelpLocks[NUM_AISLES]);
			Wait(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);
			
/*			printf("StockBoy [%d] is approached by Customer [%d] for assistance.\n", stockboy_id, stockBoyCustomerIDs[stockboy_id]);*/
			printMsg[0] = stockboy_id;
			printMsg[1] = stockBoyCustomerIDs[stockboy_id];
			printf("StockBoy [%d] is approached by Customer [%d] for assistance.\n", printMsg);
			Signal(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);

			/* wait for the customer to give the item that needs to be found. */
			Wait(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);
			stockBoyItems[stockboy_id] -= NUM_AISLES;
/*			printf("StockBoy [%d] gave aisle [%d] to Customer [%d] for item [%d].\n", stockboy_id, stockBoyItems[stockboy_id], stockBoyCustomerIDs[stockboy_id], stockBoyItems[stockboy_id]);*/
			printMsg[0] = stockboy_id;
			printMsg[1] = stockBoyItems[stockboy_id];
			printMsg[2] = stockBoyCustomerIDs[stockboy_id];
			printMsg[3] = stockBoyItems[stockboy_id];
			printf("StockBoy [%d] gave aisle [%d] to Customer [%d] for item [%d].\n", printMsg);
			Signal(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);
			
			Release(stockBoyLocks[stockboy_id]);

			/* re-acquire the help line lock */
			Acquire(aisleHelpLocks[NUM_AISLES]);
		}
		Acquire(stockBoyStatusLock);
		stockBoyAisles[stockboy_id] = -1;
		stockBoyAisleHelps[stockboy_id] = NOT_WAIT_TO_HELP;
		Release(stockBoyStatusLock);
		Release(aisleHelpLocks[NUM_AISLES]);

		/* find items to restock, first aisle that requires restocking will do */
/*		printf("StockBoy [%d] is checking if more items are to be re-stocked.\n", stockboy_id);*/
		printMsg[0] = stockboy_id;
		printf("StockBoy [%d] is checking if more items are to be re-stocked.\n", printMsg);
		for (i = 0; i < NUM_AISLES; i++) {
			Acquire(aisleLocks[(i+stockboy_id) % NUM_AISLES]);
			/* if the items on an aisle/shelf are lower than the threshold (including ones that are going to be restocked by other stockboys. */
			if ((aisleItems[(i+stockboy_id) % NUM_AISLES] + aisleRestockItems[(i+stockboy_id) % NUM_AISLES]) < MIN_ITEMS) {
/*				printf("StockBoy [%d] goes back to stock room for item [%d].\n", stockboy_id, (i+stockboy_id) % NUM_AISLES);*/
				printMsg[0] = stockboy_id;
				printMsg[1] = (i+stockboy_id) % NUM_AISLES;
				printf("StockBoy [%d] goes back to stock room for item [%d].\n", printMsg);
				restockFlag = TRUE;
				restockAisleIndex = (i+stockboy_id) % NUM_AISLES;
				aisleRestockItems[(i+stockboy_id) % NUM_AISLES]++;
				Release(aisleLocks[(i+stockboy_id) % NUM_AISLES]);
				break;
			}
			Release(aisleLocks[(i+stockboy_id) % NUM_AISLES]);
		}

		/* restock items one at a time from aisle for stock room to aisle */
		if (restockAisleIndex != -1) {
			Acquire(stockRoomWaitLock);

			/* if the stockRoomStockBoyID isn't -1, then that means someone is already in the stock room, wait */
			while (stockRoomStockBoyID != -1) {
/*				printf("StockBoy [%d] is waiting for StockBoy [%d] to leave the stock room.\n", stockboy_id, stockRoomStockBoyID);*/
				printMsg[0] = stockboy_id;
				printMsg[1] = stockRoomStockBoyID;
				printf("StockBoy [%d] is waiting for StockBoy [%d] to leave the stock room.\n", printMsg);
				Wait(stockRoomWaitCV, stockRoomWaitLock);
			}

			/* acquire the stock room lock and update stock boy ID */
			Acquire(stockRoomLock);
/*			printf("StockBoy [%d] is in stock room.\n", stockboy_id);*/
			printMsg[0] = stockboy_id;
			printf("StockBoy [%d] is in stock room.\n", printMsg);
			stockRoomStockBoyID = stockboy_id;
			Release(stockRoomWaitLock);

/*			printf("StockBoy [%d] retrieve one new item [%d] from the stock room.\n", stockboy_id, restockAisleIndex);*/
			printMsg[0] = stockboy_id;
			printMsg[1] = restockAisleIndex;
			printf("StockBoy [%d] retrieve one new item [%d] from the stock room.\n", printMsg);
			for (i = 0; i < STOCKBOY_STOCKROOM_TICK; i++) {
				Yield();
			}

			/* wake up the stock boys waiting to get into stock room */
			Acquire(stockRoomWaitLock);
			Release(stockRoomLock);
/*			printf("StockBoy [%d] leaves stock room.\n", stockboy_id);*/
			printMsg[0] = stockboy_id;
			printf("StockBoy [%d] leaves stock room.\n", printMsg);
			stockRoomStockBoyID = -1;
			Broadcast(stockRoomWaitCV, stockRoomWaitLock);
			Release(stockRoomWaitLock);

			/* leave the stock room to go to aisle */
			Acquire(stockBoyStatusLock);
			stockBoyAisles[stockboy_id] = restockAisleIndex;
			Release(stockBoyStatusLock);
			
			/* simulate the time the stock boy takes in an aisle before restocking an item */
			for (i = 0; i < STOCKBOY_AISLE_TICK; i++) {
				Yield();
			}

			/* check to see if customers need help in the aisle I am restocking the item */
			Acquire(aisleHelpLocks[restockAisleIndex]);
			while (aisleHelpLines[restockAisleIndex] > 0) {
				helpFlag = TRUE;
				Acquire(stockBoyStatusLock);
				stockBoyAisleHelps[stockboy_id] = WAIT_TO_HELP;
				Release(stockBoyStatusLock);

				/* signal anyone waiting for help, one of them */
				Signal(aisleHelpCVs[restockAisleIndex], aisleHelpLocks[restockAisleIndex]);
				aisleHelpLines[restockAisleIndex]--;
				
				/* grab my own lock, wait for them to signal me */
				Acquire(stockBoyLocks[stockboy_id]);
				Release(aisleHelpLocks[restockAisleIndex]);
				Wait(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);
				
/*				printf("StockBoy [%d] is approached by Customer [%d] for assistance.\n", stockboy_id, stockBoyCustomerIDs[stockboy_id]);*/
				printMsg[0] = stockboy_id;
				printMsg[1] = stockBoyCustomerIDs[stockboy_id];
				printf("StockBoy [%d] is approached by Customer [%d] for assistance.\n", printMsg);
				Signal(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);

				/* wait for the customer to give the item that needs to be found. */
				Wait(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);
				stockBoyItems[stockboy_id] -= NUM_AISLES;
/*				printf("StockBoy [%d] gave aisle [%d] to Customer [%d] for item [%d].\n", stockboy_id, stockBoyItems[stockboy_id], stockBoyCustomerIDs[stockboy_id], stockBoyItems[stockboy_id]);*/
				printMsg[0] = stockboy_id;
				printMsg[1] = stockBoyItems[stockboy_id];
				printMsg[2] = stockBoyCustomerIDs[stockboy_id];
				printMsg[3] = stockBoyItems[stockboy_id];
				printf("StockBoy [%d] gave aisle [%d] to Customer [%d] for item [%d].\n", printMsg);
				Signal(stockBoyCVs[stockboy_id], stockBoyLocks[stockboy_id]);
				
				Release(stockBoyLocks[stockboy_id]);

				/* re-acquire the help line lock */
				Acquire(aisleHelpLocks[restockAisleIndex]);
			}	
			Acquire(stockBoyStatusLock);
			stockBoyAisles[stockboy_id] = -1;
			Release(stockBoyStatusLock);
			Release(aisleHelpLocks[restockAisleIndex]);

			/* restock item */
			Acquire(aisleLocks[restockAisleIndex]);
			aisleItems[restockAisleIndex]++;
			aisleRestockItems[restockAisleIndex]--;
			Broadcast(aisleItemCVs[restockAisleIndex], aisleLocks[restockAisleIndex]);
			Release(aisleLocks[restockAisleIndex]);
		}

		if (restockFlag == FALSE && helpFlag == FALSE) {
			Acquire(stockBoyStatusLock);
/*			printf("StockBoy [%d] is is going on break.\n", stockboy_id);*/
			printMsg[0] = stockboy_id;
			printf("StockBoy [%d] is is going on break.\n", printMsg);
			stockBoyAisles[stockboy_id] = -1;
			stockBoyStates[stockboy_id] = ON_BREAK;
			stockBoyOnbreakLine++;
			Wait(stockBoyOnbreakCV, stockBoyStatusLock);
			stockBoyOnbreakLine--;
			Acquire(cleanupLock);
			if (cleanupFlag == FALSE) {
/*				printf("StockBoy [%d] got call from Manager.\n", stockboy_id);*/
				printMsg[0] = stockboy_id;
				printf("StockBoy [%d] got call from Manager.\n", printMsg);
			}
			Release(cleanupLock);
			stockBoyAisles[stockboy_id] = -1;
			stockBoyStates[stockboy_id] = AT_WORK;
			Release(stockBoyStatusLock);
		}

		/* if no more customers, stop the while loop, otherwise, continue */
		Acquire(cleanupLock);
		if (cleanupFlag == TRUE) {
			Release(cleanupLock);
			break;
		}
		Release(cleanupLock);
		
		Yield();
	}

	Acquire(cleanupLock);
	cleanupThreads--;
	Signal(cleanupCV, cleanupLock);
	Release(cleanupLock);
	printMsg[0] = stockboy_id;
	/*printf("StockBoy %d leaves.\n", printMsg);*/
	Exit(0);
}



void Register() {
	int register_id;
	int items = 0;
	int itemsTotal = 0;
	int difference = 0;
	/*array used for print out message*/
	int printMsg[5];

	Acquire(registerCountLock);
	register_id = registerCount;
	registerCount++;
	Release(registerCountLock);

	printMsg[0] = register_id;
	/*printf("Cash Register %d is coming online.\n", printMsg);*/
	Acquire(cleanupLock);
	cleanupThreads++;
	Release(cleanupLock);

	while (TRUE) {
		Acquire(registerLocks[register_id]);
		/* wait for the clerk / manager to use the register */
		/* if a clerk requests the register, respond */
		if (registerLines[register_id] > 0) {
			items = 0;
			itemsTotal = 0;
			registerItems[register_id] = -1;
			registerPayments[register_id] = 0;
			registerTotals[register_id] = 0;
			registerCashes[register_id] = 0;
			registerManagerMoneys[register_id] = 0;
			registerCustomerIDs[register_id] = -1;
			registerReturns[register_id] = FALSE;

			/* clerk is waiting response from register, signal */
			Signal(registerCVs[register_id], registerLocks[register_id]);
			Wait(registerCVs[register_id], registerLocks[register_id]);

			/* now wait for the clerk to provide purchase or return flag */
			
			Signal(registerCVs[register_id], registerLocks[register_id]);
			Wait(registerCVs[register_id], registerLocks[register_id]);

			/* wait for the clerk to hand over items and calculate the cost */
			while (registerItems[register_id] != -1) {
				items++;
/*				printf("Cash Register [%d] got item [%d] from Clerk [%d] to scan.\n", register_id, registerItems[register_id], register_id);*/
				printMsg[0] = register_id;
				printMsg[1] = registerItems[register_id];
				printMsg[2] = register_id;		
				printf("Cash Register [%d] got item [%d] from Clerk [%d] to scan.\n", printMsg);
				itemsTotal += itemPrices[registerItems[register_id]];
				Signal(registerCVs[register_id], registerLocks[register_id]);
				Wait(registerCVs[register_id], registerLocks[register_id]);
			}
			
/*			printf("Cash Register [%d] has scanned all [%d] items for Customer [%d].\n", register_id, items, registerCustomerIDs[register_id]);*/
			printMsg[0] = register_id;
			printMsg[1] = items;
			printMsg[2] = registerCustomerIDs[register_id];
			printf("Cash Register [%d] has scanned all [%d] items for Customer [%d].\n", printMsg);

			/* now put the calculated cost to the m.v., give to clerk */
			registerTotals[register_id] = itemsTotal;
/*			printf("Cash Register [%d] gave total cost $[%d] for Customer [%d] to Clerk [%d] for [%d] items.\n", register_id, registerTotals[register_id], registerCustomerIDs[register_id], register_id, items);*/
			printMsg[0] = register_id;
			printMsg[1] = registerTotals[register_id];
			printMsg[2] = registerCustomerIDs[register_id];
			printMsg[3] = register_id;
			printMsg[4] = items;
			printf("Cash Register [%d] gave total cost $[%d] for Customer [%d] to Clerk [%d] for [%d] items.\n", printMsg);
			Signal(registerCVs[register_id], registerLocks[register_id]);
			Wait(registerCVs[register_id], registerLocks[register_id]);

			/* if the transaction type is return, check to see if the register has enough money, or ask manager */
			if (registerReturns[register_id]) {
				registerMoneys[register_id] -= registerTotals[register_id];
				registerCashes[register_id] = registerTotals[register_id];
				clerkLineCashes[register_id] = registerCashes[register_id];

				/* if the cash register does not have enough money, ask manager */
				if (registerMoneys[register_id] < 0) {
/*					printf("Cash Register [%d] informed the manager that he needs $[%d].\n", register_id, registerMoneys[register_id]*-1);*/
					printMsg[0] = register_id;
					printMsg[1] = registerMoneys[register_id]*-1;
					printf("Cash Register [%d] informed the manager that he needs $[%d].\n", printMsg);
					registerMoneyLines[register_id]++;
					/* if manager is waiting for me, wake up him and let him give me money first */
					if (registerEmptyLines[register_id] > 0) {
						Signal(registerEmptyCVs[register_id], registerLocks[register_id]);
					}
					Wait(registerMoneyCVs[register_id], registerLocks[register_id]);
/*					printf("Cash Register [%d] received $[%d] from the manager.\n", register_id, registerManagerMoneys[register_id]);*/
					printMsg[0] = register_id;
					printMsg[1] = registerManagerMoneys[register_id];
					printf("Cash Register [%d] received $[%d] from the manager.\n", printMsg);
					registerMoneys[register_id] += registerManagerMoneys[register_id];
					registerManagerMoneys[register_id] = 0;
				}

/*				printf("Cash Register [%d] gave the money to Clerk [%d].\n", register_id, register_id);*/
				printMsg[0] = register_id;
				printMsg[1] = register_id;
				printf("Cash Register [%d] gave the money to Clerk [%d].\n", printMsg);
				Signal(registerCVs[register_id], registerLocks[register_id]);
				Wait(registerCVs[register_id], registerLocks[register_id]);
			}
			/* otherwise, ask the clerk to tell customer to pay up */
			else {
				/* wait for the money */
				if (registerPayments[register_id] == registerTotals[register_id]) {
/*					printf("Cash Register [%d] got the money from Clerk [%d].\n", register_id, register_id);*/
					printMsg[0] = register_id;
					printMsg[1] = register_id;
					printf("Cash Register [%d] got the money from Clerk [%d].\n", printMsg);
					registerMoneys[register_id] += registerPayments[register_id];
					registerPayments[register_id] = 0;
				}
				/* this line shouldn't happen, but anyway */
				else {
					/* ERROR */
/*					printf("Cash Register [%d] got the money from Clerk [%d].\n", register_id, register_id);*/
					printMsg[0] = register_id;
					printMsg[1] = register_id;
					printf("Cash Register [%d] got the money from Clerk [%d].\n", printMsg);
					registerMoneys[register_id] += registerPayments[register_id];
					registerPayments[register_id] = 0;
				}
			}

			/* give the receipt to clerk, and we are done */
/*			printf("Cash Register [%d] gave receipt to Clerk [%d] for Customer [%d].\n", register_id, register_id, registerCustomerIDs[register_id]);*/
			printMsg[0] = register_id;
			printMsg[1] = register_id;
			printMsg[2] = registerCustomerIDs[register_id];
			printf("Cash Register [%d] gave receipt to Clerk [%d] for Customer [%d].\n", printMsg);
			Signal(registerCVs[register_id], registerLocks[register_id]);
			
/*			printf("Cash Register [%d] total sale is $[%d].\n", register_id, registerMoneys[register_id]);*/
			printMsg[0] = register_id;
			printMsg[1] = registerMoneys[register_id];
			printf("Cash Register [%d] total sale is $[%d].\n", printMsg);
		}

		/* if manager is waiting to empty the cash register, response */
		if (registerEmptyLines[register_id] > 0) {
			Signal(registerEmptyCVs[register_id], registerLocks[register_id]);
			registerEmptyLines[register_id] = 0;
			Wait(registerEmptyCVs[register_id], registerLocks[register_id]);
			
			if (registerMoneys[register_id] > 0) {
/*				printf("Cash Register [%d] drawer is emptied by Manager.\n", register_id);
				printf("Cash Register [%d] total sale until now is $[%d].\n", register_id, registerMoneys[register_id]);*/
				printMsg[0] = register_id;
				printf("Cash Register [%d] drawer is emptied by Manager.\n", printMsg);
				printMsg[0] = register_id;
				printMsg[1] = registerMoneys[register_id];
				printf("Cash Register [%d] total sale until now is $[%d].\n", printMsg);

				registerMoneys[register_id] = 0;
			}
		}

		Release(registerLocks[register_id]);

		/* if no more customers, stop the while loop, otherwise, continue */
		Acquire(cleanupLock);
		if (cleanupFlag == TRUE) {
			Release(cleanupLock);
			break;
		}
		Release(cleanupLock);
		randCount++;
		Yield();
	}

	
	/* decrement the running thread counter so the main thread knows when to clean up */
	Acquire(cleanupLock);
	cleanupThreads--;
	Signal(cleanupCV, cleanupLock);
	Release(cleanupLock);
	printMsg[0] = register_id;
	/*printf("Cash Register %d is offline.\n", printMsg);*/
	Exit(0);
}



void Manager() {
	int i;
	int periodCounter = 0;
	int shutdownCounter = 0;
	int salesTotal = 0;
	int stockBoyWakeupFlag = FALSE;
	int sales[NUM_REGISTERS];

	/*arrays used to print out message*/
	int printMsg[2];

	/*printString("Manager is coming to work.\n");*/
	Acquire(cleanupLock);
	cleanupThreads++;
	Release(cleanupLock);

	

	for ( i = 0; i < NUM_REGISTERS; i++) {
		sales[i] = 0;
	}

	while (TRUE) {
		stockBoyWakeupFlag = FALSE;

		/* random announcement of the sales, 5% of the time */
		if (randCount%ANNOUNCEMENT_TICK == 0) {
			printMsg[0] = salesTotal;
			printf("-------Total Sale of the entire store until now is $[%d]--------\n", printMsg);
		}

		/* check registers for money */
		periodCounter++;
		periodCounter %= MONEY_CHECK_TICK;

		for ( i = 0; i < NUM_REGISTERS; i++) {
			Acquire(registerLocks[i]);

			if (periodCounter == 0) {
				registerEmptyLines[i]++;
			}

			/* if register needs money from manager */
			if (registerMoneyLines[i] > 0) {
				sales[i] += registerMoneys[i];
				salesTotal += registerMoneys[i];

				printMsg[0] = registerMoneys[i]*-1;
				printMsg[1] = i;	
				printf("Manager gave $[%d] to Cash Register [%d].\n", printMsg);
				registerManagerMoneys[i] = registerMoneys[i]*-1;
				Signal(registerMoneyCVs[i], registerLocks[i]);
				registerMoneyLines[i] = 0;
			}

			/* empty the cash from the registers periodically */
			if (periodCounter == 0) {
				
				Wait(registerEmptyCVs[i], registerLocks[i]);

				/* if the register is waiting money from manager, give money first. */
				if (registerMoneyLines[i] > 0) {
					sales[i] += registerMoneys[i];
					salesTotal += registerMoneys[i];
					printMsg[0] = registerMoneys[i]*-1;
					printMsg[1] = i;
					printf("Manager gave $[%d] to Cash Register [%d].\n", printMsg);
					registerManagerMoneys[i] = registerMoneys[i]*-1;
					Signal(registerMoneyCVs[i], registerLocks[i]);
					registerMoneyLines[i] = 0;
					Wait(registerEmptyCVs[i], registerLocks[i]);
				}

				if (registerMoneys[i] > 0) {
					sales[i] += registerMoneys[i];
					salesTotal += registerMoneys[i];
					/*registerMoneys[i] = 0;*/

					/*printf("Manager emptied Cash Register [%d] drawer.\n", i);
					printf("Manager has total sale of $[%d].\n", salesTotal);*/
					printMsg[0] = i;
					printf("Manager emptied Cash Register [%d] drawer.\n", printMsg);
					printMsg[0] = salesTotal;
					printf("Manager has total sale of $[%d].\n", printMsg);
				}
				registerEmptyLines[i] = 0;
				Signal(registerEmptyCVs[i], registerLocks[i]);
			}

			Release(registerLocks[i]);
		}

		/*if customers are waiting for clerks to be available, wake up a clerk */
		Acquire(clerkLineLock);
		if (clerkWakeupFlag == TRUE) {
/*			while (!clerkWakeupIDs->IsEmpty()) {
				printf("Manager got a call from Clerk [%d].\n", *(int *)clerkWakeupIDs->Remove());
			}*/
			for( i = 0; i < NUM_CLERKS; i++){
				if(clerkWakeupIDs[i] != -1){
					printMsg[0] = i;
					printf("Manager got a call from Clerk [%d].\n", printMsg);
					clerkWakeupIDs[i] = -1;
				}
			}

			clerkWakeupID = -1;
			if (clerkOnbreakLine > 0) {
				printString("Manager wakes up Clerk.\n");
				Broadcast(clerkOnbreakCV, clerkLineLock);
			}
			if (clerkWakeupLine > 0) {
				Broadcast(clerkWakeupCV, clerkLineLock);
			}
			clerkWakeupFlag = FALSE;
		}
		Release(clerkLineLock);

		/* check the stock level and set the internal flag */
		for ( i = 0; i < NUM_AISLES; i++) {
			Acquire(aisleLocks[i]);
			if ((aisleItems[i] + aisleRestockItems[i]) < MIN_ITEMS) {
				stockBoyWakeupFlag = TRUE;
				Release(aisleLocks[i]);
				break;
			}
			Release(aisleLocks[i]);
		}

		/* check help service button and set the internal flag */
		Acquire(aisleHelpLocks[NUM_AISLES]);
		if (aisleHelpFlag == TRUE) {
			stockBoyWakeupFlag = TRUE;
			aisleHelpFlag = FALSE;
		}
		Release(aisleHelpLocks[NUM_AISLES]);

		/* wake up stock boys if internal flag is set */
		Acquire(stockBoyStatusLock);
		if (stockBoyWakeupFlag == TRUE) {
			if (stockBoyOnbreakLine > 0) {
				printString("Manager wakes up StockBoy.\n");
				Broadcast(stockBoyOnbreakCV, stockBoyStatusLock);
			}
			stockBoyWakeupFlag = FALSE;
		}
		Release(stockBoyStatusLock);

		/* check to see if there is no more customer before shutting down */
		Acquire(customerLock);
		if (customerThreads == 0) {
			shutdownCounter++;
		}
		else {
			shutdownCounter = 0;
		}
		Release(customerLock);

		/* if no more customers during set ticks, set the monitor variable so other threads knows to stop looping */
		if (shutdownCounter > MANAGER_IDLE_TICK) {
			/* turn the shutdown flag to true */
			Acquire(cleanupLock);
			cleanupFlag = TRUE;
			Release(cleanupLock);

			/* check to see if any clerks are sleeping */
			Acquire(clerkLineLock);
			if (clerkOnbreakLine > 0) {
				Broadcast(clerkOnbreakCV, clerkLineLock);
			}
			Release(clerkLineLock);

			/* check to see if any stockboys are sleeping */
			Acquire(stockBoyStatusLock);
			if (stockBoyOnbreakLine > 0) {
				Broadcast(stockBoyOnbreakCV, stockBoyStatusLock);
			}
			Release(stockBoyStatusLock);
		}

		Acquire(cleanupLock);
		if (cleanupFlag == TRUE) {
			Release(cleanupLock);
			break;
		}
		Release(cleanupLock);

		randCount++;
		Yield();
	}
	
	/* print out the total sales of the store */
	for (i = 0; i < NUM_REGISTERS; i++) {
		Acquire(registerLocks[i]);
		if (registerMoneys[i] > 0) {
			sales[i] += registerMoneys[i];
			salesTotal += registerMoneys[i];

			printMsg[0] = i;
			printf("Manager emptied Cash Register [%d] drawer.\n", printMsg);
			printMsg[0] = salesTotal;
			printf("Manager has total sale of $[%d].\n", printMsg);

			printMsg[0] = i;
			printf("Cash Register [%d] drawer is emptied by Manager.\n", printMsg);
			printMsg[0] = i;
			printMsg[1] = registerMoneys[i];
			printf("Cash Register [%d] total sale until now is $[%d].\n", printMsg);

			registerMoneys[i] = 0;
		}
		Release(registerLocks[i]);
	}

	for (i = 0; i < NUM_REGISTERS; i++) {
		Acquire(registerLocks[i]);
		printMsg[0] = i;
		printMsg[1] = sales[i];
/*		printf("Total Sale from Cash Register [%d] is $[%d].\n", i, sales[i]); */
		printf("Total Sale from Cash Register [%d] is $[%d].\n", printMsg);
		Release(registerLocks[i]);
	}


	printMsg[0] = salesTotal;
	printf("Total Sale of the entire store is $[%d].\n", printMsg);

	/* decrement the running thread counter so the main thread knows when to clean up */
	Acquire(cleanupLock);
	cleanupThreads--;
	Signal(cleanupCV, cleanupLock);
	Release(cleanupLock);
	/*printString("Manager leaves.\n");*/
	Exit(0);
}


/***************************************************
      main function for execute this program
****************************************************/
int main(){
/*	char *name;
    	Thread *thread;
*/
	int idleCounter = 0;
	int i;
	int printMsg[1];

	printString("====Home Depot Simulation Test Case CUSTOM====\n");

	Initializes();

	for (i = 0; i < NUM_MANAGERS; i++) {
/*		printString("Creating Thread for Manager\n"); */
		Fork(Manager);
	}

    	for (i = 0; i < NUM_CLERKS; i++) {
/*		printMsg[0] = i;
		printf("Creating Thread for Clerk No. %d\n", printMsg); */
		Fork(Clerk);
	}

	for (i = 0; i < NUM_STOCKBOYS; i++) {
/*		printMsg[0] = i;
		printf("Creating Thread for StockBoy No. %d\n", printMsg);*/
		Fork(StockBoy);
	}

	for (i = 0; i < NUM_REGISTERS; i++) {
/*		printMsg[0] = i;
		printf("Creating Thread for Register No. %d\n", printMsg);*/
		Fork(Register);
	}

	for (i = 0; i < NUM_CUSTOMERS; i++) {
/*		printMsg[0] = i;
		printf("Creating Thread for Customer No. %d\n", printMsg);*/
		Fork(Customer);
	}

	/* idling until all threads are proper forked and up-running */
	
	while (idleCounter < MAIN_IDLE_TICK) {
		Yield();
		idleCounter++;
	}

	/* check to see if all threads have completed */

	Acquire(cleanupLock);
	while (cleanupThreads > 0) {
		Wait(cleanupCV, cleanupLock);
	}
	Release(cleanupLock);

	Cleanups();
	printString("====Home Depot Simulation Test Case CUSTOM Ends====\n");

	Exit(0);
}
